package com.keda.springdata_elasticsearch.service.impl;

import com.keda.springdata_elasticsearch.page.Page;
import com.keda.springdata_elasticsearch.service.BaseSearchService;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Auther: liuyanhui
 * @Date: 2023/01/20/ 10:53
 */
public class BaseSearchServiceImpl<T> implements BaseSearchService<T> {

    private Logger log = LoggerFactory.getLogger(getClass());
    @Resource
    private ElasticsearchRestTemplate elasticsearchTemplate;


    @Override
    public List<T> query(String keyword, Class<T> clazz) {
        NativeSearchQuery build = new NativeSearchQueryBuilder()
                .withQuery(new QueryStringQueryBuilder(keyword))
                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
                .build();
        List<T> list = new ArrayList<>();
        elasticsearchTemplate.search(build, clazz).forEach(s -> list.add(s.getContent()));
        return list;
    }

    @Override
    public List<T> queryHit(String keyword,String[] fieldNames,Class<T> clazz) {
        MultiMatchQueryBuilder queryBuilder =
                buildQueryBuilder(keyword, fieldNames);
        // 设置高亮字段
        HighlightBuilder highlightBuilder =
                builderHighlightBuilder(fieldNames);
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .build();
        SearchHits<T> search = elasticsearchTemplate.search(query, clazz);
        return getResultList(fieldNames, search);
    }

    private List<T> getResultList(String[] fieldNames, SearchHits<T> search) {
        List<T> list =new ArrayList<>();
        search.forEach(searchHit->{
            //高亮的内容
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            //将高亮的内容填充到content中
            T content = searchHit.getContent();
            Field[] fields = content.getClass().getFields();
            for (Field field : fields) {
                String name = field.getName();
                for (String fieldName : fieldNames) {
                    if(!name.equals(fieldName)){
                        continue;
                    }
                    field.setAccessible(true);
                    try {
                        field.set(content, highlightFields.get(fieldName));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            list.add(content);
        });
        return list;
    }

    @Override
    public Page<List<T>> queryHitByPage(int pageNo, int pageSize, String keyword, String[] fieldNames, Class<T> clazz) {
        MultiMatchQueryBuilder queryBuilder =
                buildQueryBuilder(keyword, fieldNames);
        // 设置高亮字段
        HighlightBuilder highlightBuilder =
                builderHighlightBuilder(fieldNames);
        PageRequest pageRequest = PageRequest.of((pageNo-1),pageSize);
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withPageable(pageRequest)
                .withHighlightBuilder(highlightBuilder)
                .build();
        SearchHits<T> search = elasticsearchTemplate.search(query, clazz);
        List<T> list = getResultList(fieldNames, search);
        Page<List<T>> page = new Page<>();
        page.setData(list);
        page.setPageNo(pageNo);
        page.setPageSize(pageSize);
        page.setTotalSize((int)search.getTotalHits());
        return page;
    }

    @Override
    public void deleteIndex(Class<T> clazz) {
        IndexOperations indexOperations = elasticsearchTemplate.indexOps(clazz);
        indexOperations.delete();
    }


    private HighlightBuilder builderHighlightBuilder(String[] fieldNames) {
        HighlightBuilder highlightBuilder = new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>");
        for (String fieldName : fieldNames) {
            highlightBuilder.field(fieldName);
        }
        return highlightBuilder;
    }

    private MultiMatchQueryBuilder buildQueryBuilder(String keyword, String[] fieldNames) {
        return QueryBuilders
                .multiMatchQuery(keyword, fieldNames)
                .analyzer("ik_max_word")
                .operator(Operator.OR);
    }
}
